#ifndef __SBSESSION_HPP_
#define __SBSESSION_HPP_

#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "../common/network/Session.hpp"
#include "../common/network/BasicBuffer.hpp"

    namespace network
    {

        namespace packet
        {
            class BasicPacket;
			class CancelOperation;
        }

        class SBSession :
        //public boost::enable_shared_from_this<SBSession>,
        public Session,
		public helper::MulticastReceiverHelper
        {
			static SBSession*						m_singleton;
			static boost::asio::io_service*			m_ioService;

			SBSession(boost::asio::io_service& _ioService);

			struct null_deleter
			{
				void operator()( void const* ) const
				{
				}
			};

			boost::shared_ptr<SBSession> shared_from_this()
			{
				boost::shared_ptr<SBSession> px( m_singleton, SBSession::null_deleter() );
				return px;
			}

		protected:

			void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd);
            
		public:

			virtual ~SBSession();

			static SBSession* create( )
			{
				if( !m_singleton )
				{
					m_singleton = new SBSession( *m_ioService );
				}	

				return m_singleton;
			}

			static SBSession* getSharedInstance( )
			{
				return m_singleton;
			}

			static void destroySharedInstance()
			{
				delete m_singleton;
				m_singleton = NULL;
			}

            void			start();
			boost::uint16_t	getSessionId();

			virtual void on_packet(buffer::BasicBuffer& _packet);
			virtual void on_packet(packet::CancelOperation& _packet);
			
			virtual void stop();


            /**
             * Function called for the first receipt on the buffer
             */
            virtual void handle_read_first_packet(const boost::system::error_code& e, std::size_t bytes_transferred);



            /**
             * Function called when new data arrived on the buffer
             */
            virtual void handle_read(const boost::system::error_code& e, std::size_t bytes_transferred);


            /**
             * Function called after writing on the socket, we get the state
             */
            virtual void handle_write(const boost::system::error_code& e, std::size_t bytes_transferred);

        protected:

			template< class T >
			struct CallableNetworkListening
			{
				CallableNetworkListening() :
					m_function(NULL),
					m_objectOwnerInstance()
				{
				}

				CallableNetworkListening( void (T::*_function)() , T* _objectOwnerInstance ) :
					m_function(_function),
					m_objectOwnerInstance( _objectOwnerInstance )
				{
				}

				void operator()()
				{
					if( m_objectOwnerInstance && m_function )
						(*(m_objectOwnerInstance).*m_function)();
				}

				void						(T::*m_function)();
				T*							m_objectOwnerInstance;

			};

			bool establishConnection( std::string _address, std::string _port);
			void sendPacketFromEvent( boost::shared_ptr< Event::EventBase> _evt );
			void receivePacketToEvent( );
		

			CallableNetworkListening<SBSession >			m_networkListeningObject;
			boost::thread									m_networkListeningThread;
			boost::thread									m_udpRequest;

            enum session_state
            {
                _not_logged_,
                _user_logged_,
                _inter_server_logged_
            };

			boost::asio::ip::tcp::resolver		m_resolver;

            /**
             * IDSession
             */
            boost::uint16_t m_sessionId;

            /**
             * Session's state
             */
            session_state m_sessionState;

			bool m_stopRequesting;

            // Save info of a running login
            //login_data::login_info login_info_;


        };

        typedef boost::shared_ptr<SBSession> sb_session_ptr;


    } // // namespace network


#endif // __SBSESSION_HPP_
